#ifndef ReferenceCounted_h__
#define ReferenceCounted_h__


//===============================================================
//
//	ReferenceCounted -- used in derived class
//
//===============================================================

namespace inf {

    class ReferenceCounted {
    public:
        virtual void release();

        inline void _add_ref() { ++ref; }
        inline void _sub_ref() { --ref; }

        inline int _get_ref() const { return ref; }
    protected:
        ReferenceCounted();
        ~ReferenceCounted() {}


        int ref;
    };

    template<class RefCountedType>
    class RefCountedHolder {
    public:
        typedef RefCountedType& reference;
        typedef RefCountedType* pointer;

        typedef const RefCountedType& const_reference;
        typedef const RefCountedType* const_pointer;

        RefCountedHolder( pointer p = 0 ) : pointee( p ) {
        }

        explicit RefCountedHolder( void* p ) : pointee( p ) {
        }

        RefCountedHolder( const RefCountedHolder& rhs ) {
            if(this == &rhs)
                return;

            if( rhs.pointee == pointee ) {
                pointee->_sub_ref();
                pointee = rhs.pointee;
                pointee->_add_ref();
            }else{
                pointee->release();
                pointee = rhs.pointee;
                pointee->_add_ref();
            }
        }

        ~RefCountedHolder() {
            if(pointee)
                pointee->release();
        }

        RefCountedHolder& operator = ( const RefCountedHolder& rhs ) {
            if(this != &rhs) {
                if( rhs.pointee == pointee ) {
                    pointee->_sub_ref();
                    pointee = rhs.pointee;
                    pointee->_add_ref();
                }else{
                    pointee->release();
                    pointee = rhs.pointee;
                    pointee->_add_ref();
                }
            }
            return *this;
        }

        int get_ref_counted() const {
            return pointee->get_ref();
        }
        pointer get_ptr() {
            return pointee;
        }
        const pointer get_ptr() const {
            return pointee;
        }

        pointer operator -> () { return get_ptr(); }
        const pointer operator -> () const { return get_ptr(); }
    private:
        pointer pointee;
    };

    template <typename T>
    void safe_release( T*& p ) {
        if( p ) {
            p->release();
            p = NULL;
        }
    }

    template <typename Iter>
    void safe_release_contents(Iter begin, Iter end) {
        for(; begin != end; ++begin ) {
            safe_release(*begin);
        }
    }


}   // ::inf

#endif // ReferenceCounted_h__
